﻿using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using UpdateApp.Config;
using UpdateApp.Download;

namespace UpdateApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, IDownloadCallback
    {
        private Task _task;
        private DownloadWrapper _downloadWrapper;
        private CancellationTokenSource _cancelSource;

        /// <summary>
        /// 数据上下文
        /// </summary>
        internal BasicDataContext BasicDataContext { get; set; }

        /// <summary>
        /// 版本相关信息
        /// </summary>
        internal VersionDto VersionInfo { get; private set; }

        /// <summary>
        /// ctor
        /// </summary>
        internal MainWindow(VersionDto version)
        {
            Init(version);
        }

        /// <summary>
        /// dispose
        /// </summary>
        public void Dispose()
        {
            _cancelSource?.Cancel();
            _task?.Dispose();
            _downloadWrapper?.Dispose();
            Environment.Exit(0);
        }

        #region IDownloadCallback
        /// <summary>
        /// <inheritdoc />
        /// </summary>
        Task IDownloadCallback.ReceiveDownloadDataAsync(DownloadDataDto data)
        {
            var (filePath, tempPath) = RemoveOldFile(data);
            if (data.DownloadType == DownloadType.Process && data.Data!.Length > 0)
            {
                BasicDataContext.ProgressbarValue = data.Progress;
                using var fileStream = new FileStream(tempPath, FileMode.Append, FileAccess.Write);
                fileStream.Write(data.Data!, 0, data.Data!.Length);
            }
            else if (data.DownloadType == DownloadType.Complete)
            {
                BasicDataContext.ProgressbarValue = data.Progress;
                BasicDataContext.DownloadShow = "Visible";
                BasicDataContext.FilePath = filePath;
                File.Move(tempPath, filePath);
                Application.Current.Dispatcher.Invoke(() =>
                {
                    var boxResult = MessageBox.Show(this, "是否现在进行更新操作", "", MessageBoxButton.YesNo, MessageBoxImage.Question);
                    if (boxResult == MessageBoxResult.Yes)
                        Install(filePath);
                });
            }

            return Task.CompletedTask;
        }
        #endregion

        #region private methods
        /// <summary>
        /// 下载程序
        /// </summary>
        private void DownloadApp()
        {
            Task.Run(async () =>
            {
                await Task.Delay(2000);
                await _downloadWrapper.GetAsync(VersionInfo.UpdateUrl, _cancelSource.Token);
            });
        }

        /// <summary>
        /// 模拟鼠标拖动
        /// </summary>
        private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DragMove();
        }

        /// <summary>
        /// 按钮事件
        /// </summary>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var btn = (Button)sender;
            switch (btn.Name)
            {
                case "btn_install":
                    Install(BasicDataContext.FilePath);
                    break;
                case "btn_exit":
                    Dispose();
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// init
        /// </summary>
        private void Init(VersionDto version)
        {
            BasicDataContext = new BasicDataContext();
            VersionInfo = version;
            _cancelSource = new CancellationTokenSource();
            DataContext = BasicDataContext;
            _downloadWrapper = new DownloadWrapper(this);
            InitializeComponent();
            DownloadApp();
        }

        /// <summary>
        /// 安装
        /// </summary>
        private void Install(string filePath)
        {
            if (File.Exists(filePath))
            {
                if (!string.IsNullOrWhiteSpace(VersionInfo.UpdateApp))
                {
                    var lastIndex = VersionInfo.UpdateApp.LastIndexOf(".");
                    if (lastIndex >= 1)
                    {
                        var oldProcess = Process.GetProcessesByName(VersionInfo.UpdateApp.Substring(0, lastIndex));
                        if (oldProcess != null)
                        {
                            foreach (var item in oldProcess)
                            {
                                item.Kill();
                                item.Dispose();
                            }
                        }
                    }
                }
                var process = Process.Start(filePath);
                //process.WaitForExit();
                process.Dispose();
            }
            else
            {
                BasicDataContext.DownloadShow = "Hidden";
                BasicDataContext.FilePath = "";
                "安装文件丢失了".ShowInfo();
            }
        }

        /// <summary>
        /// 清除老安装程序，返回对应文件地址
        /// </summary>
        private (string filePath, string tempPath) RemoveOldFile(DownloadDataDto data)
        {
            var filePath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), data.FileName!);
            var tempPath = $"{filePath}.tmp";
            if (data.IsFirstPacket && File.Exists(tempPath))
                File.Delete(tempPath);
            if (data.IsFirstPacket && File.Exists(filePath))
            {
                var fileInfo = new FileInfo(filePath);
                var processList = Process.GetProcessesByName(fileInfo.Name.TrimEnd(fileInfo.Extension.ToCharArray()));
                if (processList?.Any() == true)
                {
                    foreach (var process in processList)
                    {
                        process.Kill();
                        process.WaitForExit();
                        process.Dispose();
                    }
                }
                
                File.Delete(filePath);
            }

            return (filePath, tempPath);
        }
        #endregion
    }
}
